﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.Practices.Unity;
using Vit.Common;
using Vit.Common.Extensions;
using Vit.Common.Providers;
using Vit.Common.Helpers;
using Vit.Web.Models;
using Vit.Web.Mvc.Results;
using Vit.Web.Providers;

namespace Vit.Web.Mvc.Controllers
{
    [HandleError]
    public class DataControllerBase<TEntity> : Vit.Web.Mvc.Controllers.ControllerBase where TEntity : class
    {
        protected override void Initialize(RequestContext requestContext)
        {
            base.Initialize(requestContext);
            ViewBag.DataProvider = this.DataProvider;
        }

        [HttpGet]
        [Authorize]
        [Vit.Web.Mvc.Attributes.Widget]
        public virtual ActionResult Index(string id)
        {
            FormCollection filterForm = DataProvider.InitialSearchConditions();
            ViewBag.FilterForm = filterForm;

            var query = DataProvider.Search(filterForm);

            int pageIndex = 1;
            if (!string.IsNullOrWhiteSpace(Request.QueryString["pi"]))
                int.TryParse(Request.QueryString["pi"], out pageIndex);
            int pageSize = 20;
            if (!string.IsNullOrWhiteSpace(this.Request.QueryString["ps"]))
                int.TryParse(this.Request.QueryString["ps"], out pageSize);

            PagerList<TEntity> result = new PagerList<TEntity>(query, pageIndex, pageSize);
            ViewBag.Paging = result.PagingInfo;
            SetViewTitle("Index");
            return View("DataIndex", result);
        }

        [HttpPost]
        [Authorize]
        public virtual ActionResult Index(FormCollection filterForm)
        {
            ViewBag.FilterForm = filterForm;

            var query = DataProvider.Search(filterForm);

            int pageIndex = 1;
            if (!string.IsNullOrWhiteSpace(filterForm["pi"]))
                int.TryParse(filterForm["pi"], out pageIndex);
            int pageSize = 20;
            if (!string.IsNullOrWhiteSpace(this.Request.Form["ps"]))
                int.TryParse(this.Request.Form["ps"], out pageSize);

            PagerList<TEntity> result = new PagerList<TEntity>(query, pageIndex, pageSize);
            ViewBag.Paging = result.PagingInfo;
            SetViewTitle("Index");
            return View("DataIndex", result);
        }

        [HttpGet]
        [Authorize]
        [Vit.Web.Mvc.Attributes.Widget]
        public virtual ActionResult Create(string id)
        {
            TEntity obj = DataProvider.New();
            SetViewTitle("Create");
            return View("DataCreate", obj);
        }

        [HttpPost]
        [Authorize]
        public virtual ActionResult Create(TEntity obj)
        {
            if (this.ModelState.IsValid)
            {
                try
                {
                    obj = DataProvider.SetDefaultValues(obj);
                    obj = DataProvider.Insert(obj);
                    return SaveView("DataIndex", obj);
                }
                catch (Exception ex)
                {
                    ViewBag.Message = ex.GetBaseException().Message;
                }
            }
            SetViewTitle("Create");
            return View("DataCreate", obj);
        }

        [HttpGet]
        [Authorize]
        [Vit.Web.Mvc.Attributes.Widget]
        public virtual ActionResult Edit(string id)
        {
            object[] ids = UnFormatKeys(id);
            TEntity entity = DataProvider.GetByKeys(ids);
            ViewData["EntityID"] = id;
            SetViewTitle("Edit");
            return View("DataEdit", entity);
        }

        [HttpPost]
        [Authorize]
        public virtual ActionResult Edit(TEntity obj, FormCollection form)
        {
            if (this.ModelState.IsValid)
            {
                string id = form["EntityID"];

                object[] ids = UnFormatKeys(id);
                TEntity entity = DataProvider.GetByKeys(ids);
                if (this.TryUpdateModel<TEntity>(entity))
                {
                    try
                    {
                        obj = DataProvider.Modify(entity);
                        return SaveView("DataEdit", obj);
                    }
                    catch (Exception ex)
                    {
                        ViewBag.Message = ex.GetBaseException().Message;
                    }
                }
            }
            SetViewTitle("Edit");
            return View("DataEdit", obj);
        }

        [HttpGet]
        [Authorize]
        public virtual ActionResult Delete(string id)
        {
            object[] ids = UnFormatKeys(id);
            TEntity entity = DataProvider.GetByKeys(ids);
            if (entity != null)
            {
                DataProvider.Delete(entity);
            }
            return RedirectToAction("Index");
        }

        [HttpPost]
        [Authorize]
        public virtual ActionResult Delete(FormCollection form)
        {
            foreach (string fid in form.AllKeys.Where(o => o.StartsWith("cb_")))
            {
                string val = form[fid];
                object[] ids = UnFormatKeys(val);
                TEntity entity = DataProvider.GetByKeys(ids);
                if (entity != null)
                {
                    try
                    {
                        if (entity is IEntityWithStatus)
                        {
                            ((IEntityWithStatus)entity).Status = DataStatus.Deleted;
                            DataProvider.Modify(entity);
                        }
                        else
                        {
                            DataProvider.Delete(entity);
                        }
                    }
                    catch (Exception ex)
                    {
                        ViewBag.Message = ex.GetBaseException().Message;
                    }
                }
            }
            return DeleteView("Index");
        }

        [HttpGet]
        [Authorize]
        [Vit.Web.Mvc.Attributes.Widget]
        public virtual ActionResult Detail(string id)
        {
            object[] ids = UnFormatKeys(id);
            TEntity entity = DataProvider.GetByKeys(ids);
            ViewData["EntityID"] = id;
            SetViewTitle("Detail");
            return View("DataDetail", entity);
        }

        [NonAction]
        protected virtual ActionResult SaveView(string viewName, object model)
        {
            SetViewTitle(viewName);
            if (ViewBag.Message == null)
                ViewBag.Message = Locale.GetString("Vit.Web", "DataController_SaveSuccessfully");
            return Refresh();
        }

        [NonAction]
        protected virtual ActionResult DeleteView(string viewName)
        {
            SetViewTitle(viewName);
            if (ViewBag.Message == null)
                ViewBag.Message = Locale.GetString("Vit.Web", "DataController_DeleteSuccessfully");
            return RedirectToAction(viewName);
        }

        [NonAction]
        protected virtual void SetViewTitle(string viewName)
        {
        }

        protected virtual string FormatKeys(params object[] ids)
        {
            return string.Join("$", ids);
        }

        protected virtual object[] UnFormatKeys(string id)
        {
            return id.Split(new char[] { '$' }, StringSplitOptions.RemoveEmptyEntries);
        }

        protected virtual IDataProvider<T> GetDataProvider<T>(string dataProviderName) where T : class
        {
            if (string.IsNullOrWhiteSpace(dataProviderName))
                return Unity.Current.Resolve<IDataProvider<T>>();
            return Unity.Current.Resolve<IDataProvider<T>>(dataProviderName);
        }

        protected virtual IDataProvider<TEntity> DataProvider
        {
            get
            {
                if (string.IsNullOrWhiteSpace(DataProviderName))
                    return Unity.Current.Resolve<IDataProvider<TEntity>>();
                return Unity.Current.Resolve<IDataProvider<TEntity>>(DataProviderName);
            }
        }

        protected virtual string DataProviderName
        {
            get { return string.Empty; }
        }
    }
}
